requirements.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. from pip._vendor.packaging.utils import canonicalize_name
  2. from pip._internal.utils.typing import MYPY_CHECK_RUNNING
  3. from .base import Requirement, format_name
  4. if MYPY_CHECK_RUNNING:
  5. from pip._vendor.packaging.specifiers import SpecifierSet
  6. from pip._internal.req.req_install import InstallRequirement
  7. from .base import Candidate, CandidateLookup
  8. class ExplicitRequirement(Requirement):
  9. def __init__(self, candidate):
  10. # type: (Candidate) -> None
  11. self.candidate = candidate
  12. def __repr__(self):
  13. # type: () -> str
  14. return "{class_name}({candidate!r})".format(
  15. class_name=self.__class__.__name__,
  16. candidate=self.candidate,
  17. )
  18. @property
  19. def name(self):
  20. # type: () -> str
  21. # No need to canonicalise - the candidate did this
  22. return self.candidate.name
  23. def format_for_error(self):
  24. # type: () -> str
  25. return self.candidate.format_for_error()
  26. def get_candidate_lookup(self):
  27. # type: () -> CandidateLookup
  28. return self.candidate, None
  29. def is_satisfied_by(self, candidate):
  30. # type: (Candidate) -> bool
  31. return candidate == self.candidate
  32. class SpecifierRequirement(Requirement):
  33. def __init__(self, ireq):
  34. # type: (InstallRequirement) -> None
  35. assert ireq.link is None, "This is a link, not a specifier"
  36. self._ireq = ireq
  37. self._extras = frozenset(ireq.extras)
  38. def __str__(self):
  39. # type: () -> str
  40. return str(self._ireq.req)
  41. def __repr__(self):
  42. # type: () -> str
  43. return "{class_name}({requirement!r})".format(
  44. class_name=self.__class__.__name__,
  45. requirement=str(self._ireq.req),
  46. )
  47. @property
  48. def name(self):
  49. # type: () -> str
  50. canonical_name = canonicalize_name(self._ireq.req.name)
  51. return format_name(canonical_name, self._extras)
  52. def format_for_error(self):
  53. # type: () -> str
  54. # Convert comma-separated specifiers into "A, B, ..., F and G"
  55. # This makes the specifier a bit more "human readable", without
  56. # risking a change in meaning. (Hopefully! Not all edge cases have
  57. # been checked)
  58. parts = [s.strip() for s in str(self).split(",")]
  59. if len(parts) == 0:
  60. return ""
  61. elif len(parts) == 1:
  62. return parts[0]
  63. return ", ".join(parts[:-1]) + " and " + parts[-1]
  64. def get_candidate_lookup(self):
  65. # type: () -> CandidateLookup
  66. return None, self._ireq
  67. def is_satisfied_by(self, candidate):
  68. # type: (Candidate) -> bool
  69. assert candidate.name == self.name, \
  70. "Internal issue: Candidate is not for this requirement " \
  71. " {} vs {}".format(candidate.name, self.name)
  72. # We can safely always allow prereleases here since PackageFinder
  73. # already implements the prerelease logic, and would have filtered out
  74. # prerelease candidates if the user does not expect them.
  75. spec = self._ireq.req.specifier
  76. return spec.contains(candidate.version, prereleases=True)
  77. class RequiresPythonRequirement(Requirement):
  78. """A requirement representing Requires-Python metadata.
  79. """
  80. def __init__(self, specifier, match):
  81. # type: (SpecifierSet, Candidate) -> None
  82. self.specifier = specifier
  83. self._candidate = match
  84. def __repr__(self):
  85. # type: () -> str
  86. return "{class_name}({specifier!r})".format(
  87. class_name=self.__class__.__name__,
  88. specifier=str(self.specifier),
  89. )
  90. @property
  91. def name(self):
  92. # type: () -> str
  93. return self._candidate.name
  94. def format_for_error(self):
  95. # type: () -> str
  96. return "Python " + str(self.specifier)
  97. def get_candidate_lookup(self):
  98. # type: () -> CandidateLookup
  99. if self.specifier.contains(self._candidate.version, prereleases=True):
  100. return self._candidate, None
  101. return None, None
  102. def is_satisfied_by(self, candidate):
  103. # type: (Candidate) -> bool
  104. assert candidate.name == self._candidate.name, "Not Python candidate"
  105. # We can safely always allow prereleases here since PackageFinder
  106. # already implements the prerelease logic, and would have filtered out
  107. # prerelease candidates if the user does not expect them.
  108. return self.specifier.contains(candidate.version, prereleases=True)